package com.iflytek.autofly.setting.biz.networking;

import android.app.Activity;
import android.text.TextUtils;

import com.iflytek.autofly.bluetoothservice.aidl.RRBluetoothDevice;
import com.iflytek.autofly.bluetoothservice.util.BluetoothServiceCons;
import com.iflytek.autofly.setting.R;
import com.iflytek.autofly.utils.FlyLog;

import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <b>Description: </b>蓝牙设置的fragment<br/>
 * <b>Change History:</b><br/>
 * <table border="1">
 * <tr>
 * <td><b>user</b></td>
 * <td><b>date</b></td>
 * <td><b>time</b></td>
 * <td><b>reason</b></td>
 * </tr>
 * <tr>
 * <td>JunLuan@iflytek.com</td>
 * <td>2015年5月26日</td>
 * <td>上午11:29:58</td>
 * <td>创建此文件</td>
 * </tr>
 * <tr>
 * <td>junluan@iflytek.com</td>
 * <td>2015年6月19日</td>
 * <td>下午2:58:00</td>
 * <td>基于统一的蓝牙服务重构代码</td>
 * </tr>
 * </table>
 *
 * @author JunLuan@iflytek.com
 */
public class BluetoothSetting {


    private static final String TAG = "BluetoothSetting";
    private static final int THREAD_QUIT = 0x1001;
    private static final int THREAD_WORKING = 0x1002;
    BlockingQueue<OnStatusChangedTask> mWorkList = new LinkedBlockingQueue<OnStatusChangedTask>();
    private Activity mActivity;
    private FlyBluetoothManager mBtManager;
    private IBtViewChangedListener mViewChanger;
    private AtomicInteger mServiceReady = new AtomicInteger(0);
    // onstatuschanged 不一定在同一线程中被调用，扔到同一线程处理，防止UI错乱
    private Thread onStatusChangedThread;
    private FlyBluetoothManager.IBtConnectStateUpdater mBtConnectStateUpdater =
            new FlyBluetoothManager.IBtConnectStateUpdater() {

                @Override
                public void onStatusChanged(RRBluetoothDevice rrDevice, int changeState) {
                    try {
                        mWorkList.put(new OnStatusChangedTask(THREAD_WORKING, rrDevice, changeState));
                    } catch (InterruptedException e) {
                        FlyLog.e(TAG, e);
                    }
                }

                @Override
                public void onListChanged() {
                    FlyLog.d(TAG, "onListChanged");
                    updateDeviceList();
                }

                @Override
                public void onServiceBound() {
                    FlyLog.d(TAG, "enter");
                    initInfo();
                }

                @Override
                public void onScanStart() {
                    if (mViewChanger != null) {
                        mViewChanger.onScanStart();
                    }
                }

                @Override
                public void onScanEnd() {
                    if (mViewChanger != null) {
                        mViewChanger.onScanEnd();
                    }
                }

                @Override
                public void onDeviceFound(final RRBluetoothDevice rrBluetoothDevice) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            if (mViewChanger != null) {
                                mViewChanger.onDeviceFound();
                            }
                            int state = rrBluetoothDevice.getState();
                            String name = rrBluetoothDevice.getName();
                            String addr = rrBluetoothDevice.getAddress();
                            if (state != BluetoothServiceCons.ConnectionStatus.CONNECTION_UNPAIRED) {
                                return;
                            }
                            FlyLog.d(TAG, "onDeviceFound|name=" + name + ",addr=" + addr + ",state=" + state);
                            final BtDeviceBean bean = new BtDeviceBean(
                                    name, addr,
                                    statusToString(state), state, getActionByStatus(state));
                            mActivity.runOnUiThread(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                            if (mViewChanger != null) {
                                                final BtDeviceListAdapter adapter = mViewChanger
                                                        .getAdapter();
                                                adapter.addScan(bean);
                                                adapter.notifyDataSetChanged();
                                            }
                                        }
                                    }
                            );
                        }
                    }).start();
                }
            };

    public BluetoothSetting() {
    }

    public void fini() {
        FlyLog.d(TAG, "enter");
        mServiceReady.set(0);
        mBtManager.fini();
        mBtManager = null;
        try {
            mWorkList.put(new OnStatusChangedTask(THREAD_QUIT, null, 0));
        } catch (InterruptedException e) {
            FlyLog.e(TAG, e);
        }
    }

    public void onResume() {
        FlyLog.d(TAG, "enter");

        if (mBtManager == null) {
            mBtManager = FlyBluetoothManager.getInstance();
            mBtManager.init(mActivity, mBtConnectStateUpdater);
            updateInfo(false);
        }
    }

    public void onPause() {
    }


    public void initInfo() {
        if (mServiceReady.incrementAndGet() < 2) {
            return;
        }
        updateInfo(true);

        onStatusChangedThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true) {
                        OnStatusChangedTask t = mWorkList.take();
                        if (t.id == THREAD_QUIT) {
                            FlyLog.e(TAG, "onStatusChangedThread|quit");
                            return;
                        }

                        FlyLog.d(TAG, "onStatusChangedThread");

                        final RRBluetoothDevice device = t.rrDevice;
                        final int status = t.changeState;
                        FlyLog.d(TAG, "onStatusChangedThread|" + device.getName() + "," + device.getAddress() + "," + status);

                        // 极端情况下，正在连接会在已连接后面处理，导致UI出错，因此在此处兜底
                        if (!TextUtils.isEmpty(device.getAddress())
                                && status == BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTING) {
                            if (mViewChanger != null) {
                                BtDeviceListAdapter adapter = mViewChanger.getAdapter();
                                BtDeviceBean bean = adapter.getItem(device.getAddress());
                                if (bean != null) {
                                    if (bean.getState() == BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTED) {
                                        FlyLog.w(TAG, "wrong state, try to verify it");
                                        continue;
                                    }
                                }
                            }
                        }

                        // 状态改变，当前已连接设备先置空
                        if (mViewChanger != null) {
                            mViewChanger.setConnectDeviceName(null);
                        }

                        BtDeviceBean bean = new BtDeviceBean(
                                device.getName(), device.getAddress(),
                                statusToString(status), status, getActionByStatus(status));

                        if (!TextUtils.isEmpty(bean.getAddr())) {
                            if (mViewChanger != null) {
                                BtDeviceListAdapter adapter = mViewChanger.getAdapter();
                                adapter.setItem(bean);
                            }
                        } else {
                            // 某些情况，addr为空，改变当前设备的状态
                            if (mViewChanger != null) {
                                BtDeviceListAdapter adapter = mViewChanger.getAdapter();
                                adapter.setItem(0, status,
                                        statusToString(status), getActionByStatus(status));
                            }
                        }

                        // 已连接设备，设置当前连接设备名称
                        if (status == BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTED) {
                            if (mViewChanger != null) {
                                mViewChanger.setConnectDeviceName(bean.getName());
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    FlyLog.e(TAG, e);
                }
                FlyLog.e(TAG, "onStatusChangedThread|abort");

            }
        });

        onStatusChangedThread.start();
    }

    public void updateInfo(boolean needUpdateList) {
        if (mBtManager != null) {
            String name = mBtManager.getName();
            FlyLog.d(TAG, "name=" + name);
            String linkedDevice = mBtManager.getCurrnetDeviceName();
            if (mViewChanger != null) {
                mViewChanger.onNameChanged(name);
                mViewChanger.setConnectDeviceName(linkedDevice);
                mViewChanger.onAutoConnectChanged(mBtManager.getAutoConnect());
            }
            if (needUpdateList) {
                updateDeviceList();
                //mManager.startScan();
            }
        }
    }

    public void init(Activity ctx, IBtViewChangedListener changer) {
        mActivity = ctx;
        mViewChanger = changer;
        if (mBtManager == null) {
            mBtManager = FlyBluetoothManager.getInstance();
        }
        mBtManager.init(mActivity, mBtConnectStateUpdater);
        initInfo();

    }

    private void updateDeviceList() {
        FlyLog.d(TAG, "updateDeviceList");

        if (mBtManager != null) {
            ArrayList<RRBluetoothDevice> deviceList = mBtManager
                    .getDeviceList();
            BtDeviceListAdapter adpt = null;
            if (mViewChanger != null) {
                adpt = mViewChanger.getAdapter();
            }
            if (adpt == null) {
                return;
            }
            adpt.clearList();
            FlyLog.d(TAG, "updateDeviceList | device: " + deviceList.size());
            for (int i = 0; i < deviceList.size(); i++) {
                RRBluetoothDevice device = deviceList.get(i);
                if (device == null) {
                    FlyLog.e(TAG, "device [" + i + "] in list is null");
                    continue;
                }
                if (TextUtils.isEmpty(device.getAddress())) {
                    FlyLog.e(TAG, "address of device [" + i + "] in list is null");
                    continue;
                }

                BtDeviceBean model = new BtDeviceBean(device.getName(), device.getAddress(), statusToString(device.getState()), device.getState(), getActionByStatus(device.getState()));
                adpt.add(model);
                if (device.getState() == BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTED) {
                    if (mViewChanger != null) {
                        mViewChanger.setConnectDeviceName(device.getName());
                    }
                }
            }
            adpt.notifyDataSetChanged();
        }
    }

    private String statusToString(int status) {
        switch (status) {
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECT_FAILED:
                return mActivity.getString(R.string.net_bt_status_connect_failed);
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_DISCONNECT:
                return mActivity.getString(R.string.net_bt_status_paired);
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTED:
                return mActivity.getString(R.string.net_bt_status_connected);
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTING:
                return mActivity.getString(R.string.net_bt_status_connecting);
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_UNPAIRED:
                return mActivity.getString(R.string.net_bt_status_unpaired);
            default:
                FlyLog.e(TAG, "unknown status[" + status + "]");
                return mActivity.getString(R.string.net_bt_status_unpaired);
        }
    }

    private String getActionByStatus(int status) {
        switch (status) {
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECT_FAILED:
                return mActivity.getString(R.string.net_bt_action_connect_failed);
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_DISCONNECT:
                return mActivity.getString(R.string.net_bt_action_paired);
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTED:
                return mActivity.getString(R.string.net_bt_action_connected);
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTING:
                return mActivity.getString(R.string.net_bt_action_connecting);
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_UNPAIRED:
                return mActivity.getString(R.string.net_bt_action_unpaired);
            default:
                FlyLog.e(TAG, "unknown status[" + status + "]");
                return mActivity.getString(R.string.net_bt_action_unpaired);
        }
    }

    public String getName() {
        return mBtManager.getName();
    }

    public void setName(String result) {
        if (mBtManager == null) {
            FlyLog.e(TAG, "no invalid manager");
            return;
        }
        if (mViewChanger != null) {
            mViewChanger.onNameChanged(result);
        }
        mBtManager.setName(result);
    }

    public String getLinkedDEviceName() {
        if (mBtManager != null) {
            String name = mBtManager.getCurrnetDeviceName();
            if (name != null) {
                return name;
            }
        }
        return "";
    }

    public void connect(BtDeviceBean bean) {
        mBtManager.connect(bean);
    }

    public void unpair(BtDeviceBean bean) {
        if (mViewChanger != null) {
            mViewChanger.getAdapter().removeItem(bean);
            mBtManager.cancelConnect(bean);
            mBtManager.unpair(bean);
        }

    }

    public void cancelConnect(BtDeviceBean bean) {
        mBtManager.cancelConnect(bean);
    }

    public void scan() {
        if (mBtManager != null) {
            mBtManager.startScan();
        }
    }

    public boolean getAutoConnect() {
        return mBtManager.getAutoConnect();
    }

    public void setAutoConnect(boolean autoConnect) {
        mBtManager.setAutoConnect(autoConnect);
    }

    public boolean ready() {
        return mServiceReady.get() >= 2;
    }

    public void stopScan() {
        if (mBtManager != null) {
            mBtManager.stopScan();
        }
    }

    public interface IBtViewChangedListener {
        void onNameChanged(final String btName);

        void onPinChanged(final String btPin);

        BtDeviceListAdapter getAdapter();

        void onAutoConnectChanged(final boolean autoConnect);

        void onDeviceFound();

        void onScanStart();

        void onScanEnd();

        void setConnectDeviceName(String name);
    }

    class OnStatusChangedTask {
        int id;
        RRBluetoothDevice rrDevice;
        int changeState;

        public OnStatusChangedTask(int id, RRBluetoothDevice rrDevice, int changeState) {
            this.id = id;
            this.rrDevice = rrDevice;
            this.changeState = changeState;
    }
    }
}
